﻿
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace Mono.Cecil {

	public sealed class TypeDefinitionCollection : Collection<TypeDefinition> {

		ModuleDefinition container;

		public TypeDefinition this [string fullname] {
			get {
				var position = fullname.IndexOf ('/');
				if (position > 0)
					return GetNestedType (fullname);

				foreach (var type in this)
					if (type.FullName == fullname)
						return type;

				return null;
			}
		}

		TypeDefinition GetNestedType (string fullname)
		{
			var names = fullname.Split ('/');
			var type = this [names [0]];

			for (int i = 1; i < names.Length; i++) {
				var nested_types = type.NestedTypes;
				for (int j = 0; j < nested_types.Count; j++) {
					var nested_type = nested_types [j];
					if (nested_type.Name != names [i])
						continue;

					type = nested_type;
					break;
				}
			}

			return type;
		}

		internal TypeDefinitionCollection (ModuleDefinition container)
		{
			this.container = container;
		}

		protected override void SetItem (int index, TypeDefinition type)
		{
			base.SetItem (index, type);

			Attach (type);
		}

		protected override void InsertItem (int index, TypeDefinition type)
		{
			base.InsertItem (index, type);

			Attach (type);
		}

		protected override void RemoveItem (int index)
		{
			var item = this [index];

			base.RemoveItem (index);

			Detach (item);
		}

		protected override void ClearItems ()
		{
			foreach (var type in this)
				Detach (type);

			base.ClearItems ();
		}

		void Attach (TypeDefinition type)
		{
			if (type.Module != null && type.Module != container)
				throw new ArgumentException ("Type already attached, clone it instead");

			type.Module = container;
		}

		void Detach (TypeDefinition type)
		{
			type.Module = null;
		}
	}
}
